// ffi foreign function interface
// 外部函数接口
// 因为 epoll 等系统调用都是由 C语言编写而成，因此想要调用它们，必须满足 C语言的调用约定
// 因此 Rust 提供了 link 这个宏来告诉编译器帮助生存满足 C语言 ABI 的函数调用

pub const EPOLL_CTL_ADD: i32 = 1;
pub const EPOLL_CTL_DEL: i32 = 2;
pub const EPOLL_CTL_MOD: i32 = 3;

pub const EPOLLHUP: i32 = 0x10;
pub const EPOLLIN: i32 = 0x1;
pub const EPOLLMSG: i32 = 0x400;
pub const EPOLLONESHOT: i32 = 0x40000000;
pub const EPOLLOUT: i32 = 0x4;
pub const EPOLLPRI: i32 = 0x2;
pub const EPOLLRDBAND: i32 = 0x80;
pub const EPOLLRDHUP: i32 = 0x2000;

#[link(name = "c")]
extern "C" {
    // epoll 是 Linux 提供的一种 I/O 时间通知机制
    // epoll 的核心是 epoll 实例，它是一种内核数据结构，但是却由用户空间来定义
    // epoll 可以被认为是包含了 interest 列表和 ready 列表的容器
    // -interest 被注册为监听的文件描述符集合
    // -ready I/O事件准备就绪的文件描述符集合
    // epoll API:
    // epoll_create(2) 新建一个 epoll 实例，并返回这个实例的文件描述符
    // epoll_ctl(2) 给 epoll 实例添加或删除感兴趣文件描述符和感兴趣IO事件
    // epoll_wait(2) 等待IO事件的产生，如果没有IO时间则会阻塞当前调用线程
    // 新建 epoll 实例
    // size 参数可以直接忽略，大于 0 即可
    pub fn epoll_create(size: i32) -> i32;
    #[allow(dead_code)]
    pub fn epoll_create1(flags: i32) -> i32;

    // 关闭一个文件描述符
    pub fn close(fd: i32) -> i32;

    // 控制 epoll 监听的描述符
    pub fn epoll_ctl(epfd: i32, op: i32, fd: i32, event: *mut EpollEvent) -> i32;

    // 等待 epoll 事件
    pub fn epoll_wait(epfd: i32, events: *mut EpollEvent, maxevents: i32, timeout: i32) -> i32;
}

#[repr(C, packed)]
pub union EpollData {
    pub(crate) ptr: *const std::os::raw::c_void,
    pub(crate) fd: i32,
    pub(crate) uint32: u32,
    pub(crate) uint64: u64,
}

#[repr(C, packed)]
pub struct EpollEvent {
    pub(crate) events: u32, // epoll 事件个数
    pub(crate) data: EpollData,
}
